#include "uart.h"
#include <stdarg.h>

static void uart_putc(char c);

void uart_init(void) 
{
    UART1_UCR1 = 0x00000000;
    UART1_UCR2 = 0x00000000;
    UART1_UCR2 |= (1 << 0);  // ????
    UART1_UCR2 |= (1 << 1);  // ????
    UART1_UCR2 |= (1 << 2);  // ?? UART
    UART1_UCR2 |= (1 << 5);  // 8 ???
    UART1_UCR2 |= (1 << 6);  // 1 ???

    UART1_UCR3 = 0x00000000;
    UART1_UFCR = 0x00000000;
    UART1_UFCR |= (1 << 7);  // ?? FIFO

    UART1_UBIR = 0x0000000F;
    UART1_UBMR = 0x0000016C;

    UART1_UCR1 |= (1 << 0);
}

static void uart_putc(char c) 
{
    while (!(UART1_USR2 & (1 << 3)));  // ?????????
    UART1_UTXD = c;
}

void uart_puts(const char *str) 
{
    while (*str) {
        uart_putc(*str++);
    }
}

#include <stdarg.h>
#include <stdint.h>

void _putchar(char c)
{
    uart_putc(c);

}

static void print_string(const char *str) {
    while (*str) {
        _putchar(*str++);
    }
}

static void print_dec(int32_t num) {
    if (num < 0) {
        _putchar('-');
        num = -num;
    }
    
    char buffer[12];
    int8_t i = 0;
    
    do {
        buffer[i++] = (num % 10) + '0';
        num /= 10;
    } while (num > 0);
    
    while (--i >= 0) {
        _putchar(buffer[i]);
    }
}

static void print_hex(uint32_t num, uint8_t uppercase) {
    const char *digits = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
    char buffer[9];
    int8_t i = 0;
    
    do {
        buffer[i++] = digits[num % 16];
        num /= 16;
    } while (num > 0);
    
    while (--i >= 0) {
        _putchar(buffer[i]);
    }
}

int printf(const char *format, ...) 
{
    va_list args;
    va_start(args, format);
    
    while (*format) {
        if (*format == '%') {
            format++;
            switch (*format) {
                case 'c': {
                    char c = va_arg(args, int);
                    _putchar(c);
                    break;
                }
                case 's': {
                    char *str = va_arg(args, char *);
                    print_string(str);
                    break;
                }
                case 'd': {
                    int32_t num = va_arg(args, int32_t);
                    print_dec(num);
                    break;
                }
                case 'u': {
                    uint32_t num = va_arg(args, uint32_t);
                    print_dec(num);
                    break;
                }
                case 'x': {
                    uint32_t num = va_arg(args, uint32_t);
                    print_hex(num, 0);
                    break;
                }
                case 'X': {
                    uint32_t num = va_arg(args, uint32_t);
                    print_hex(num, 1);
                    break;
                }
                case 'p': {
                    void *ptr = va_arg(args, void *);
                    print_string("0x");
                    print_hex((uint32_t)ptr, 0);
                    break;
                }
                case '%': {
                    _putchar('%');
                    break;
                }
                default:
                    _putchar('%');
                    _putchar(*format);
                    break;
            }
        } else {
            _putchar(*format);
        }
        format++;
    }
    
    va_end(args);
    return 0;
}



